using System;
using System.Collections.Generic;
using System.Text;
using Gj.aliyun;
using Gj.DarkLoong;
using Gj.Galaxy.Logic;
using NaughtyAttributes;
using Newtonsoft.Json;
using SimpleJSON;
using UnityEngine;

namespace Gj
{
    public class BaseUISpace : MonoBehaviour
    {
        public delegate void UiFinishDelegate();

        public string sceneName;
        public NodeHelper Node;
        public bool needLogin = true;
        public bool needProject;
        public string pageProject;
        public ScreenHandle ScreenHandle;
        public BasePage Page;

        private async void Awake()
        {
            await Project.Init();
            Page = InitPage();
            if (Page != null)
            {
                InitBaseEvent();
                InitSceneEvent();
                InitTeamEvent();
                InitRoomEvent();
                if (!AuthConnect.IsLogin) InitLoginEvent();
            }

            InitBefore();
            Page.param = History.InitScene(sceneName);
            LogTools.Log("prev:" + Page.PrevScene);
            Page.PrevScene = History.Prev();
            Project.SetPage(Page, false);
            if (!needProject)
            {
                Init();
                Project.SetPage(Page, true, pageProject);
                InitAfter();
                Page.BindNode(Node);
            }

            Project.Flow(() =>
            {
                if (needProject)
                {
                    LogTools.Log("needProject");
                    Init();
                    Project.SetPage(Page, true, pageProject);
                    InitAfter();
                    Page.BindNode(Node);
                }

                LogTools.Log("login: " + AuthConnect.IsLogin + ", needlogin: " + needLogin + AuthConnect.player.Instance);
                if (!AuthConnect.IsLogin && needLogin && !Project.Single)
                    Project.AuthFlow("", token =>
                    {
                        AuthConnect.OauthList(strings =>
                        {
                            if (strings == null || strings.Length == 0) return;
                            var info = ChannelManager.Info();
                            if (info.id == null) return;
                            // 登录
                            foreach (var k in strings)
                            {
                                SocialManager.Platform p;
                                if (SocialManager.LocalPlatform.TryGetValue(k, out p))
                                    if (info.social.Contains(p))
                                    {
                                        SocialManager.SilenceLogin(p, null, null);
                                        break;
                                    }
                            }
                        });
                    });
            }, true);
        }

        protected virtual void Update()
        {
            Page?.Update();
        }

        protected void OnDestroy()
        {
            Page?.Destroy();
        }

        public event UiFinishDelegate OnUiFinishEvent;

        protected virtual void InitBefore()
        {
        }

        protected virtual void InitAfter()
        {
        }

        protected virtual void Init()
        {
        }

        public void Connect()
        {
            OnConnect();
        }

        public void Reconnect()
        {
            OnReconnect();
        }

        protected virtual void OnConnect()
        {
        }

        protected virtual void OnReconnect()
        {
        }

        [Button]
        public virtual void LoadUiRef()
        {
#if UNITY_EDITOR && !UNITY_SERVER
            FileTools.LoadScript("Assets/Projects/game/Page/" + sceneName + "Page.cs",
                "game.Page." + sceneName + "Page");
            LoadTextRef(FileTools.LoadText("Assets/Resources/Bundle/Common/Language/Chinese.txt"));
#endif
        }

        public void LoadTextRef(string text)
        {
#if UNITY_EDITOR
            var map = Localization.Cov(text);
            foreach (var item in map) RefData.AddRef(UIKey.LOCAL_KEY, item.Key, item.Value);
#endif
        }

        protected virtual BasePage InitPage()
        {
            return new BasePage();
        }

        protected void InitBaseEvent()
        {
            var channelInfo = ChannelManager.Info();
            SocialManager.Bind(p => { Page.Send(SystemMessage.SocialLogout); });
            // 跳转场景
            Page.On(SystemEvent.JumpScene, (string scene) => { History.Jump(scene); });
            Page.On(SystemEvent.JumpScene, info => { History.Jump(info["scene"], info); });
            // 返回之前的场景
            Page.On(SystemEvent.BackScene, () => { History.Back(); });
            // 返回之前的场景
            Page.On(SystemEvent.ReplaceScene, (string scene) => { History.Replace(scene); });
            Page.On(SystemEvent.ReplaceScene, () => { History.Replace(History.CurrentScene); });
            // 分享
            Page.On(SystemEvent.ShareWechat, (JSONObject o) => { });
            // 统计
            Page.On(SystemEvent.Stat, (string e) => { AuthConnect.Stat(e); });
            Page.On(SystemEvent.Feedback, (string message) =>
            {
                AnalyticsManager.Event("feedback", new Dictionary<string, object> { { "message", message } });
                AuthConnect.Feedback(message);
            });

            // 预加载广告
            Page.On(SystemEvent.PreAd, key =>
            {
                var k = key.Split('|');
                AdManager.PreLoad(k[0], AdManager.GetPlatform(k[1]), AdManager.AdType.Reward);
            });
            Page.On(SystemEvent.ShowAd, key =>
            {
                var k = key.Split('|');
                LogTools.Info("show ad:" + key);
                Game.single.StartCoroutine(AdManager.ShowAd(k[0], AdManager.GetPlatform(k[1]), AdManager.AdType.Reward,
                    b =>
                    {
                        LogTools.Info("ad result:" + b);
                        Page.Send(SystemMessage.ShowAdSuccess, b);
                    }));
            });

            Page.On(SystemEvent.ChangeName, (string name) =>
            {
                AnalyticsManager.Event("changeName", new Dictionary<string, object> { { "name", name } });

                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    await UnityCloud.Auth.UpdateName(name);
                });
                AuthConnect.Change(name, "", (success, err) =>
                {
                    if (success)
                        Page.Send(SystemMessage.ChangeNameSuccess);
                    else
                        Page.Send(SystemMessage.GalaxyError, err);
                });
            });
            Page.On(SystemEvent.ChangeAvatar, (string avatar) =>
            {
                AnalyticsManager.Event("changeAvatar", new Dictionary<string, object> { { "avatar", avatar } });
                AuthConnect.Change("", avatar, (success, err) =>
                {
                    if (success)
                        Page.Send(SystemMessage.ChangeAvatarSuccess);
                    else
                        Page.Send(SystemMessage.GalaxyError, err);
                });
            });
            Page.On(SystemEvent.ChangeCountry, (string country) =>
            {
                AnalyticsManager.Event("changeCountry", new Dictionary<string, object> { { "country", country } });
                AuthConnect.ChangeCountry(country, (success, err) =>
                {
                    if (success)
                        Page.Send(SystemMessage.ChangeCountrySuccess);
                    else
                        Page.Send(SystemMessage.GalaxyError, err);
                });
            });
            Page.On(SystemEvent.GetPreference,
                (string key) =>
                {
                    AuthConnect.GetPreference(preferences =>
                    {
                        Page.Send(SystemMessage.GetPreference, preferences[key]);
                    });
                });
            Page.On(SystemEvent.GetPreference,
                () => { AuthConnect.GetPreference(preferences => { Page.Send(SystemMessage.GetPreference); }); });
            Page.On(SystemEvent.UpdatePreference, (JSONObject info) =>
            {
                var data = new Dictionary<string, object>();
                var e = info.GetEnumerator();
                while (e.MoveNext())
                {
                    var c = (KeyValuePair<string, JSONNode>)e.Current;
                    data.Add(c.Key, c.Value);
                }

                AnalyticsManager.Event("updatePreference", data);
                AuthConnect.UpdatePreference(data);
            });
            Page.On(SystemEvent.GetRealStatus, () =>
            {
                if (!channelInfo.needReal)
                {
                    var result = new JSONObject();
                    result["needReal"] = false;
                    result["isUnderAge"] = false;
                    result["isMoreTime"] = false;
                    result["duration"] = 0;
                    Page.Send(SystemMessage.GetRealStatus, result);
                    return;
                }

                // Antiaddiction.Valid(Im.CurrentUser, info =>
                // {
                //     var result = new JSONObject();
                //     if (info == null)
                //     {
                //         // 没有正常完成实名认证
                //         result["needReal"] = true;
                //     }
                //     else
                //     {
                //         result["needReal"] = false;
                //         result["isUnderAge"] = info.IsUnderAge;
                //         result["duration"] = info.RemainingTimeInMinutes;
                //     }
                //
                //     Page.Send(SystemMessage.GetRealStatus, result);
                // });

                if (Project.Single)
                {
                    SocialManager.Real(SocialManager.localPlayer.Platform, (p, code, message) =>
                    {
                        var info = new JSONObject();
                        info["needReal"] = AuthConnect.realInfo.NeedReal;
                        info["isUnderAge"] = AuthConnect.realInfo.IsUnderAge;
                        info["isMoreTime"] = AuthConnect.realInfo.IsMoreTime;
                        info["duration"] = AuthConnect.realInfo.Duration;
                        Page.Send(SystemMessage.GetRealStatus, info);
                    });
                    return;
                }
                AuthConnect.GetRealStatus((realInfo) =>
                {
                    var info = new JSONObject();
                    info["needReal"] = realInfo.NeedReal;
                    info["isUnderAge"] = realInfo.IsUnderAge;
                    info["duration"] = realInfo.Duration;
                    // needReal: true->游客，查看duration，false->实名，查看isUnderAge
                    // isUnderAge: true->未成年，查看duration，false->成年，没有限制
                    // duration: 今日还剩游戏时长
                    if (realInfo.NeedReal && SocialManager.IsReal(SocialManager.localPlayer.Platform))
                    {
                        SocialManager.Real(SocialManager.localPlayer.Platform, (p, code, message) =>
                          {
                              if (code == SocialManager.SUCCESS)
                              {
                                  // 小米需要重新验证session来确保实名
                                  AuthLoginIn(SocialManager.localPlayer.Platform, SocialManager.localPlayer.message, (player, msg) =>
                                {
                                    if (player == null)
                                    {
                                        // 如果session过期，重新授权（应该不会）
                                        AuthLogin(SocialManager.localPlayer.Platform, ((gamePlayer, dictionary) => Page.Trigger(SystemEvent.GetRealStatus)));
                                        return;
                                    }
                                    Page.Trigger(SystemEvent.GetRealStatus);
                                });
                              }
                          });
                        return;
                    }
                    Page.Send(SystemMessage.GetRealStatus, info);
                });
            });

            Page.On(SystemEvent.GetCount, target =>
            {
                AuthConnect.GetCount(new[] { target }, false, b =>
                {
                    if (b != null)
                        Page.Send(SystemMessage.GetCount, new JSONObject { { "target", target }, { "count", b[0] } });
                });
            });

            Page.On(SystemEvent.GenerateName, (string language) =>
            {
                AuthConnect.GenerateName(language, b =>
                {
                    if (b != null) Page.Send(SystemMessage.GenerateName, new JSONObject { { "nickname", b } });
                });
            });

            Page.On(SystemEvent.SetRead, target => { AuthConnect.GetCount(new[] { target }, true, b => { }); });

            Page.On(SystemEvent.SetRealInfo,
                (JSONObject info) =>
                {
                    AuthConnect.SetRealInfo(info["id"], info["name"],
                        b => { Page.Send(SystemMessage.SetRealStatus, b); });
                });
            Page.On(SystemEvent.GetChannel, () =>
            {
                var info = new JSONObject();
                info["channel"] = channelInfo.channel;
                info["id"] = channelInfo.id;
                info["needReal"] = channelInfo.needReal;
                info["isChina"] = channelInfo.isChina;
                Page.Send(SystemMessage.GetChannel, info);
            });
            Page.On(SystemEvent.SubmitLeaderboard, (JSONObject info) =>
            {
                if (SocialManager.localPlayer == null) return;

                SocialManager.SubmitLeaderboard(info["identity"], info["value"], SocialManager.localPlayer.Platform,
                    (p, code, message) =>
                    {
                        if (code == SocialManager.SUCCESS)
                        {
                        }
                    });
            });
            Page.On(SystemEvent.AddAchievement, (string identity) =>
            {
                if (SocialManager.localPlayer == null) return;

                SocialManager.AddAchievement(identity, 0, SocialManager.localPlayer.Platform,
                    (p, code, message) =>
                    {
                        if (code == SocialManager.SUCCESS)
                        {
                        }
                    });
            });
            Page.On(SystemEvent.Logout, () =>
            {
                Logout();
            });
            Page.On(SystemEvent.Permission, (string permission) =>
            {
                var define = AndroidPermission.ToDefine(permission);
                AndroidPermission.Request(define);
            });
            Page.On(SystemEvent.UpdateLocation, (string scene) =>
            {
                switch (channelInfo.channel)
                {
                    case "taptap":
                        TapTap.Update.NeedUpdate();
                        break;
                }
            });
            // Page.On(SystemEvent.ConnectChat, (string s) =>
            // {
            //     LogTools.Log("connectChat:" + s);
            //     Im.Connect(s, false);
            // });
            // Page.On(SystemEvent.ConnectOpenChat, (string s) =>
            // {
            //     LogTools.Log("connectOpenChat:" + s);
            //     Im.Connect(s, true);
            // });
            // Page.On(SystemEvent.LeaveChat, (string s) =>
            // {
            //     LogTools.Log("leaveChat:" + s);
            //     Im.Leave(s);
            // });
            // Page.On(SystemEvent.OpenChat, (string s) =>
            // {
            //     LogTools.Log("OpenChat:" + s);
            //     Im.Open(s);
            // });
            // Page.On(SystemEvent.CloseChat, (string s) =>
            // {
            //     LogTools.Log("CloseChat:" + s);
            //     Im.Close(s);
            // });
            // Page.On(SystemEvent.ResetChat, () =>
            // {
            //     LogTools.Log("resetChat");
            //     Im.Reset();
            // });

            // Page.On(SystemEvent.GetUpdateFriendChat, () =>
            // {
            //     LogTools.Log("getUpdateFriendChat");
            //     var prefix = Im.ParseChannel("friend:*");
            //     Im.UpdateList(prefix);
            // });
            // Page.On(SystemEvent.GetListChat, (string key) =>
            // {
            //     LogTools.Log("getListChat:" + key);
            //     var prefix = Im.ParseChannel(key + ":*");
            //     Im.GetList(prefix);
            // });
            // Page.On(SystemEvent.SendChat, (JSONObject message) =>
            // {
            //     LogTools.Log("SendChat:" + message);
            //     Project.ProjectUpdate.Queue.Enqueue(async () =>
            //     {
            //         await Im.Send(message["channel"], message["content"]);
            //     });
            // });
            Page.On(SystemEvent.TouchThreshold, (float f) =>
            {
                ScreenHandle.touchThreshold = f;
            });
            Page.On(SystemEvent.SaveRecord, (JSONObject result) =>
            {
                var player = AuthConnect.player;
                // LogTools.Log($"save record start: {result} {instance} {id}");
                Aliyun.SaveRecord(result, player.GetPlayerId(), ((b, s) =>
                {
                    // LogTools.Log($"save record end: {b}, {s}");
                }));
            });
            Page.On(SystemEvent.LoadRecord, () =>
            {
                var player = AuthConnect.player;
                // LogTools.Log($"load record start: {instance} {id}");
                Aliyun.LoadRecord(player.GetPlayerId(), ((b, s) =>
                {
                    // LogTools.Log($"load record end: {b}, {s}");
                    Page.Send(SystemMessage.LoadRecord, s != null ? s.AsObject : new JSONObject());
                }));
            });
            Page.On(SystemEvent.ShareLocal, (JSONObject result) =>
            {
                // Debug.Log($"Share start: {result}");
                var player = AuthConnect.player;
                var platform = SocialManager.LocalPlatform[player.Instance["platform"]];
                SocialManager.DirectShare(platform, result["title"], result["image"], result["description"], "", "",
                    (p, stCode, errorMsg) =>
                    {
                        // Debug.Log($"Share end: {p} {stCode} {errorMsg}");
                    });
            });
            Page.On(SystemEvent.JumpOut, (string id) =>
            {
                TapTap.TapTap.Scene(id);
            });
        }

        protected void InitLoginEvent()
        {
            Page.On(SystemEvent.IsAuthorized, () =>
            {
                var token = CacheTools.GetVal("userToken", "");
                if (string.IsNullOrEmpty(token))
                {
                    Page.Send(SystemMessage.IsAuthorized, new JSONObject());
                    return;
                }
                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    await DarkLoong.DarkLoong.Token(token, (JSONObject info) =>
                    {
                        AuthConnect.player.Inited(info);
                        AuthConnect.player.Id = AuthConnect.player.Instance["id"];
                        AuthConnect.player.UserId = AuthConnect.player.Instance["userId"];
                        AuthConnect.Token = Auth.SessionToken;
                        info["isAuthorized"] = true;
                        Page.Send(SystemMessage.IsAuthorized, info);
                    }, (err) =>
                    {
                        
                    });
                });
                return;
                var e = SocialManager.LocalPlatform.GetEnumerator();
                var flag = false;
                while (e.MoveNext())
                    if (SocialManager.CanAuth(e.Current.Value))
                    {
                        LogTools.Process("{0} install", e.Current.Key);
                        SocialManager.SilenceLogin(e.Current.Value,
                            message =>
                            {
                                SocialManager.SaveLocal(e.Current.Value, message);
                                var info = new JSONObject();
                                info["nickName"] = message.TryGetValue("nickName", out var nickName) ? nickName : "";
                                info["avatar"] = message.TryGetValue("avatar", out var avatar) ? avatar : "";
                                info["isAuthorized"] = true;
                                LogTools.Log($"is authorized {info}");
                                Page.Send(SystemMessage.IsAuthorized, info);
                            },
                            () => Page.Send(SystemMessage.IsAuthorized, new JSONObject())
                        );
                        flag = true;
                        break;
                    }
                e.Dispose();
                if (!flag)
                    Page.Send(SystemMessage.IsAuthorized, new JSONObject());
            });
            Page.On(SystemEvent.Authorized, () =>
            {
                var e = SocialManager.LocalPlatform.GetEnumerator();
                var flag = false;
                while (e.MoveNext())
                    if (SocialManager.CanAuth(e.Current.Value))
                    {
                        LogTools.Process("{0} install", e.Current.Key);
                        SocialManager.SilenceLogin(e.Current.Value,
                            message => AuthLoginIn(e.Current.Value, message),
                            () => AuthLogin(e.Current.Value)
                        );
                        flag = true;
                        break;
                    }
            });
            
            Page.On(SystemEvent.CodeLogin, (string code) =>
            {
                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    await DarkLoong.DarkLoong.Code(code, LoginSuccess, LoginFail);
                });
            });

            Page.On(SystemEvent.TestLogin, () =>
            {
                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    var token = CacheTools.GetVal("userToken", "");
                    if (!string.IsNullOrEmpty(token))
                    {
                        await DarkLoong.DarkLoong.Token(token, LoginSuccess, LoginFail);
                    }
                    else
                    {
                        await DarkLoong.DarkLoong.Guest(LoginSuccess, LoginFail);
                    }
                });
            });
            
            Page.On(SystemEvent.AuthLogin, (int platform) =>
            {
                var p = (SocialManager.Platform)platform;
                AuthLogin(p);
            });
            Page.On(SystemEvent.GuestLogin, () =>
            {
                // AuthLogin(SocialManager.Platform.TapTap);
                AnalyticsManager.Event("guestLogin");
                AuthConnect.Guest(player => { Project.SaveLoginToken(player, null); });
            });

            Page.On(SystemEvent.SyncInfo, () =>
            {
                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    await DarkLoong.Auth.ChangeInfo(AuthConnect.player.Instance["nickName"].Value, AuthConnect.player.Instance["avatar"].Value);
                    Page.Send(SystemMessage.SyncInfoSuccess);
                });
            });
        }
        
        void Logout()
        {
            LogTools.Process("Logout");
            Auth.Logout();
            CacheTools.SetVal("userToken", "");
            Project.UnAuthFlow();
            if (SocialManager.localPlayer != null)
                SocialManager.Logout(SocialManager.localPlayer.Platform,
                    p => { Page.Send(SystemMessage.LogoutSuccess); });
            else
                Page.Send(SystemMessage.LogoutSuccess);
        }

        void LoginSuccess(JSONObject info)
        {
            AuthConnect.player.Inited(info);
            LoginSuccess(AuthConnect.player);
        }

        void LoginSuccess(GamePlayer player)
        {
            LogTools.Process("LoginSuccess");
            AuthConnect.player.Id = player.Instance["id"];
            AuthConnect.player.UserId = player.Instance["userId"];
            AuthConnect.Token = Auth.SessionToken;
            Project.SaveLoginToken(player, player.Instance["nickName"] ? player.Instance["nickName"] : null);
        }

        void LoginFail(string err)
        {
            LogTools.Process("LoginFail");
            Page.Send(SystemMessage.LoginFail, err);
        }

        protected void AuthLogin(SocialManager.Platform platform,
            Action<GamePlayer, Dictionary<string, string>> callback = null)
        {
            if (callback == null)
                callback = (player, message) =>
                {
                    if (player == null)
                    {
                        LoginFail("exception");
                    }
                    else
                    {
                        LoginSuccess(player);
                    }
                };
            var channel = SocialManager.ChannelPlatform[platform];
            AnalyticsManager.Event(channel + "Login");

            switch (SocialManager.AuthTypePlatform[platform])
            {
                case SocialManager.AuthType.Oauth:
                    OauthLogin(platform, channel, callback);
                    break;
                case SocialManager.AuthType.AppOauth:
                    AppOauthLogin(platform, channel, callback);
                    break;
                case SocialManager.AuthType.AppOfflineOauth:
                default:
                    OfflineLogin(platform, channel, callback);
                    break;
            }
        }

        protected void AuthLoginIn(SocialManager.Platform platform, Dictionary<string, string> message,
            Action<GamePlayer, Dictionary<string, string>> callback = null)
        {
            SocialManager.SaveLocal(platform, message);
            if (callback == null)
                callback = (player, msg) =>
                {
                    if (player == null)
                    {
                        LoginFail("exception");
                    }
                    else
                    {
                        LoginSuccess(player);
                    }
                };

            var channel = SocialManager.ChannelPlatform[platform];
            switch (SocialManager.AuthTypePlatform[platform])
            {
                case SocialManager.AuthType.Oauth:
                    OauthLoginIn(platform, channel, message, callback);
                    break;
                case SocialManager.AuthType.AppOauth:
                    AppOauthLoginIn(platform, channel, message, callback);
                    break;
                case SocialManager.AuthType.AppOfflineOauth:
                default:
                    OfflineLoginIn(platform, channel, message, callback);
                    break;
            }
        }

        protected void OfflineLogin(SocialManager.Platform p, string channel,
            Action<GamePlayer, Dictionary<string, string>> callback)
        {
            SocialManager.Authorize(p, (platform, code, message) =>
            {
                if (code == SocialManager.SUCCESS)
                {
                    SocialManager.SaveLocal(p, message);
                    OfflineLoginIn(p, channel, message, callback);
                }
                else
                    LoginFail("authError");
            });
        }

        protected void OfflineLoginIn(SocialManager.Platform p, string channel, Dictionary<string, string> message,
            Action<GamePlayer, Dictionary<string, string>> callback)
        {
            var result = JsonConvert.SerializeObject(message); // openId, nickName, unionId, avatar, sessionToken
            if (Project.Single)
            {
                AuthConnect.player.UserId = message["openId"];
                AuthConnect.Token = message["openId"];
                JSONObject info = new JSONObject();
                info["nickName"] = message["nickName"];
                info["openId"] = message["openId"];
                info["unionId"] = message["unionId"];
                info["avatar"] = message["avatar"];
                info["platform"] = SocialManager.DefinePlatform[p];
                AuthConnect.player.Inited(info);
                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    try
                    {
                        await DarkLoong.DarkLoong.Login(SocialManager.AuthType.AppOfflineOauth, channel, AuthConnect.player);
                        callback(AuthConnect.player, message);
                    }catch(Exception e){
                        callback(null, message);
                    }
                });
                return;
            }
            AuthConnect.AppOfflineOauth(channel, result, player => { callback(player, message); });
        }

        protected void OauthLogin(SocialManager.Platform p, string channel,
            Action<GamePlayer, Dictionary<string, string>> callback)
        {
            SocialManager.Authorize(p, (platform, code, message) =>
            {
                if (code == SocialManager.SUCCESS)
                {
                    SocialManager.SaveLocal(p, message);
                    OauthLoginIn(p, channel, message, callback);
                }
                else
                    LoginFail("authError");
            });
        }

        protected void OauthLoginIn(SocialManager.Platform p, string channel, Dictionary<string, string> message,
            Action<GamePlayer, Dictionary<string, string>> callback)
        {
            if (Project.Single)
            {
                JSONObject info = new JSONObject();
                info["platform"] = SocialManager.DefinePlatform[p];
                info["code"] = message["code"];
                info["state"] = message["state"];
                AuthConnect.player.Inited(info);

                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    try
                    {
                        await DarkLoong.DarkLoong.Login(SocialManager.AuthType.Oauth, channel, AuthConnect.player);
                        callback(AuthConnect.player, message);
                    }catch(Exception e){
                        callback(null, message);
                    }
                });
                return;
            }
            AuthConnect.Oauth(channel, message["code"], message["state"], player => { callback(player, message); });
        }

        protected void AppOauthLogin(SocialManager.Platform p, string channel,
            Action<GamePlayer, Dictionary<string, string>> callback)
        {
            SocialManager.Authorize(p, (platform, code, message) =>
            {
                if (code == SocialManager.SUCCESS)
                {
                    // todo move to SocialManager inline
                    SocialManager.SaveLocal(p, message);
                    AppOauthLoginIn(p, channel, message, callback);
                }
                else
                    LoginFail("authError");
            });
        }

        protected void AppOauthLoginIn(SocialManager.Platform p, string channel, Dictionary<string, string> message,
            Action<GamePlayer, Dictionary<string, string>> callback)
        {
            if (Project.Single)
            {
                AuthConnect.player.UserId = message["openId"];
                AuthConnect.Token = message["openId"];
                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    try
                    {
                        await DarkLoong.DarkLoong.Login(SocialManager.AuthType.AppOauth, channel, AuthConnect.player);
                        callback(AuthConnect.player, message);
                    }catch(Exception e){
                        callback(null, message);
                    }
                });
                return;
            }
            AuthConnect.AppOauth(channel, message["openId"], message["accessToken"],
                player => { callback(player, message); });
        }

        protected void InitSceneEvent()
        {
            Page.On(SystemEvent.InviteFriend, (string target) => { AuthConnect.InviteFriend(target); });
            Page.On(SystemEvent.ConfirmFriend, (string target) => { AuthConnect.ConfirmFriend(target, true); });
            Page.On(SystemEvent.CancelFriend, (string target) => { AuthConnect.ConfirmFriend(target, false); });
            Page.On(SystemEvent.SceneJoinLobby, (JSONObject o) =>
            {
                LogTools.Info("System: {0}", o);
                var lobby = o["lobby"];
                o.Remove("lobby");
                var option = new Dictionary<string, object>();
                var e = o.GetEnumerator();
                while (e.MoveNext())
                {
                    var c = (KeyValuePair<string, JSONNode>)e.Current;
                    option.Add(c.Key,
                        c.Value.IsNumber ? c.Value.AsInt : c.Value.ToString().TrimStart('"').TrimEnd('"'));
                }

                AnalyticsManager.Event("joinLobby", option);
                if (TeamConnect.IsConnected())
                    TeamConnect.JoinLobby(lobby, option,
                        success => { Page.Send(SystemMessage.SceneJoinLobby, success); });
                else
                    SceneConnect.JoinLobby(lobby, option,
                        success => { Page.Send(SystemMessage.SceneJoinLobby, success); });
            });
            Page.On(SystemEvent.SceneLeaveLobby, (bool team) =>
            {
                if (team)
                {
                    if (TeamConnect.IsConnected())
                        TeamConnect.LeaveLobby();
                    else
                        SceneConnect.LeaveLobby(b => { Page.Send(SystemMessage.SceneLeaveLobby, b); });
                }
                else
                {
                    if (TeamConnect.IsConnected()) TeamConnect.Leave();
                    SceneConnect.LeaveLobby(b => { Page.Send(SystemMessage.SceneLeaveLobby, b); });
                }
            });

            // Page.On(SystemEvent.SceneBatchUpdateLeaderboard,
            //     (JSONArray o) =>
            //     {
            //         var result = new JSONObject();
            //         result["identity"] = o["identity"];
            //         if (Project.Single)
            //         {
            //             LeanCloud.Leaderboard.BatchUpdate(o,
            //                 success =>
            //                 {
            //                     result["result"] = success;
            //                     Page.Send(SystemMessage.SceneBatchUpdateLeaderboard, result);
            //                 });
            //             return;
            //         }
            //         SceneConnect.UpdateLeaderboard(o["identity"], o["value"],
            //             success =>
            //             {
            //                 result["result"] = success;
            //                 Page.Send(SystemMessage.SceneBatchUpdateLeaderboard, result);
            //             });
            //     });
            // Page.On(SystemEvent.SceneUpdateLeaderboard,
            //     (JSONObject o) =>
            //     {
            //         var result = new JSONObject();
            //         result["identity"] = o["identity"];
            //         if (Project.Single)
            //         {
            //             LeanCloud.Leaderboard.Update(o["identity"], o["value"],
            //                 success =>
            //                 {
            //                     result["result"] = success;
            //                     Page.Send(SystemMessage.SceneUpdateLeaderboard, result);
            //                 });
            //             return;
            //         }
            //         SceneConnect.UpdateLeaderboard(o["identity"], o["value"],
            //             success =>
            //             {
            //                 result["result"] = success;
            //                 Page.Send(SystemMessage.SceneUpdateLeaderboard, result);
            //             });
            //     });
            // Page.On(SystemEvent.SceneNumberLeaderboard,
            //     (string identity) =>
            //     {
            //         var result = new JSONObject();
            //         result["identity"] = identity;
            //         if (Project.Single)
            //         {
            //             // LeanCloud.Leaderboard.Number(identity,
            //             //     rank =>
            //             //     {
            //             //         result["result"] = rank;
            //             //         Page.Send(SystemMessage.SceneNumberLeaderboard, result);
            //             //     });
            //             return;
            //         }
            //         SceneConnect.NumberLeaderboard(identity,
            //             rank =>
            //             {
            //                 result["result"] = rank;
            //                 Page.Send(SystemMessage.SceneNumberLeaderboard, result);
            //             });
            //     });
            Page.On(SystemEvent.SceneListLeaderboard,
                (string identity) =>
                {
                    var listResult = new JSONObject();
                    var selfResult = new JSONObject();
                    listResult["identity"] = identity;
                    selfResult["identity"] = identity;
                    // Debug.LogError("leaderboard list");
                    DarkLoong.Leaderboard.List(identity, 100,
                        (list, self) =>
                        {
                            listResult["result"] = list;
                            selfResult["result"] = self["rank"].AsInt;
                            selfResult["value"] = self["value"].AsInt;
                            Page.Send(SystemMessage.SceneListLeaderboard, listResult);
                            Page.Send(SystemMessage.SceneNumberLeaderboard, selfResult);
                        });
                });
            Page.On(SystemEvent.SceneHistoryLeaderboard,
                (JSONObject info) =>
                {
                    var result = new JSONObject();
                    result["identity"] = info["identity"];
                    result["version"] = info["version"];
                    if (Project.Single)
                    {
                        LeanCloud.Leaderboard.History(info["version"], info["identity"], 100,
                            rank =>
                            {
                                result["result"] = rank;
                                Page.Send(SystemMessage.SceneHistoryLeaderboard, result);
                                LeanCloud.Leaderboard.HistoryNumber(info["version"], info["identity"],
                                    rank =>
                                    {
                                        result["result"] = rank;
                                        Page.Send(SystemMessage.SceneNumberLeaderboard, result);
                                    });
                            });
                        return;
                    }
                });
            Page.On(SystemEvent.ValidCode, (string code) =>
            {
                DarkLoong.RedemptionCode.Valid(code, (JSONArray data, string err) =>
                {
                    if (err != "")
                    {
                        Page.Send(SystemMessage.Error, err);
                    }
                    else
                    {
                        Page.Send(SystemMessage.ValidCode, data);
                    }
                });
            });
            Page.On(SystemEvent.Online, () =>
            {
                Project.ProjectUpdate.Queue.Enqueue(async () =>
                {
                    var result = await DarkLoong.Auth.Online();
                    var err = Api.GetError(result);
                    if (err != "")
                    {
                        // AUTH_SSO: 在其他地方登录
                        // AUTH_ERROR: 登录数据错误
                        Page.Send(SystemMessage.AuthError, err);
                    }
                    LogTools.Log(result.ToString());
                });
            });
            // Page.On(SystemEvent.MapCustomList,
            //     (JSONObject search) =>
            //     {
            //         DarkLoong.Map.CustomList(search["new"].AsBool, search["hot"].AsBool, search["my"].AsBool, search["collect"].AsBool, search["page"].AsInt, search["size"].AsInt,
            //             (list) =>
            //             {
            //                 search["result"] = list;
            //                 Page.Send(SystemMessage.MapCustomList, search);
            //             });
            //     });
            // Page.On(SystemEvent.MapCustomCreate, (JSONObject o) =>
            //     {
            //         DarkLoong.Map.CustomCreate(o["title"], o["desc"], o["t"], o["data"].AsObject, (o, m) =>
            //         {
            //             Page.Send(SystemMessage.MapCustomCreate, o);
            //         });
            //     });
            // Page.On(SystemEvent.MapCustomLike, (JSONObject o) =>
            // {
            //     // action: do, undo
            //     DarkLoong.Map.CustomLike(o["no"], o["action"], (i =>
            //     {
            //         Page.Send(SystemMessage.MapCustomLike, i);
            //     }));
            // });
            // Page.On(SystemEvent.MapCustomCollect, (JSONObject o) =>
            // {
            //     // action: do, undo
            //     DarkLoong.Map.CustomCollect(o["no"], o["action"], (i =>
            //     {
            //         Page.Send(SystemMessage.MapCustomCollect, i);
            //     }));
            // });
            // Page.On(SystemEvent.MapEvent, (JSONObject o) =>
            // {
            //     // category: custom,
            //     // event: battle, battle_success
            //     // meta: { value, controy }
            //     DarkLoong.Map.Event(o["category"], o["no"], o["event"], o["meta"].AsObject, (i =>
            //     {
            //         Page.Send(SystemMessage.MapEvent, i);
            //     }));
            // });
        }

        protected void InitTeamEvent()
        {
            // 组队邀请
            Page.On(SystemEvent.TeamInvite, (string targetId) =>
            {
                // 判断是否在队伍中
                if (TeamConnect.IsConnected())
                    TeamConnect.Invite(targetId, success => { Page.Send(SystemMessage.TeamInvited, success); });
                else
                    SceneConnect.CreateTeam(Game.TeamMaxNum, token =>
                    {
                        LogTools.Action("Create Team: {0} -> {1}", "token", token, Game.TeamMaxNum);
                        TeamConnect.Join(token, s =>
                        {
                            Page.Send(SystemMessage.TeamCreate, "");
                            TeamConnect.Invite(targetId, success => { Page.Send(SystemMessage.TeamInvited, success); });
                        });
                    });
            });
            Page.On(SystemEvent.TeamCreate, (string next) =>
            {
                // 判断是否在队伍中
                if (TeamConnect.IsConnected())
                    Page.Send(SystemMessage.TeamCreate, next);
                else
                    SceneConnect.CreateTeam(Game.TeamMaxNum, token =>
                    {
                        LogTools.Action("Create Team: {0} -> {1}", "token", token, Game.TeamMaxNum);
                        TeamConnect.Join(token, s => { Page.Send(SystemMessage.TeamCreate, next); });
                    });
            });
            // 组队踢人
            Page.On(SystemEvent.TeamKickPlayer, (string targetId) =>
            {
                if (TeamConnect.IsConnected()) TeamConnect.KickPlayer(targetId);
            });
            Page.On(SystemEvent.TeamLeavePlayer, () =>
            {
                if (TeamConnect.IsConnected()) TeamConnect.Leave();
            });
            Page.On(SystemEvent.TeamJoinPlayer, (string token) => { TeamConnect.Join(token, b => { }); });
            Page.On(SystemEvent.TeamJoinLobby, (JSONObject o) =>
            {
                if (TeamConnect.IsConnected())
                {
                    var lobby = o["lobby"];
                    o.Remove("lobby");
                    var option = new Dictionary<string, object>();
                    var e = o.GetEnumerator();
                    while (e.MoveNext())
                    {
                        var c = (KeyValuePair<string, JSONNode>)e.Current;
                        option.Add(c.Key,
                            c.Value.IsNumber ? c.Value.AsInt : c.Value.ToString().TrimStart('"').TrimEnd('"'));
                    }

                    TeamConnect.JoinLobby(lobby, option,
                        success => { Page.Send(SystemMessage.SceneJoinLobby, success); });
                }
            });
            Page.On(SystemEvent.TeamLeaveLobby, () =>
            {
                if (TeamConnect.IsConnected()) TeamConnect.LeaveLobby();
            });
            Page.On(SystemEvent.TeamReadyPlayer, (JSONObject o) =>
            {
                if (TeamConnect.IsConnected())
                    TeamConnect.ReadyPlayer(o["status"], o["location"] != null ? o["location"].Value : "");
            });
            Page.On(SystemEvent.TeamRefresh, () =>
            {
                if (TeamConnect.IsConnected()) TeamConnect.Refresh();
            });
        }

        protected void InitRoomEvent()
        {
            Page.On(SystemEvent.RoomInitPlayer, (JSONObject data) =>
            {
                LogTools.Action("Room", "RoomInitPlayer: {0}", data.ToString());
                var id = data["id"].Value;
                ConnectManager.RoomService?.Init(id, Encoding.UTF8.GetBytes(data.ToString()));
                // RoomConnect.ConnectGame(token, (GameBeforeListener)this);
            });
            Page.On(SystemEvent.RoomJoinPlayer, (string id) =>
            {
                LogTools.Action("Room", "RoomJoin: {0}", id);
                AnalyticsManager.Event("joinRoom");
                ConnectManager.RoomService?.Join(id, Game.GetVersion());
                // RoomConnect.ConnectGame(token, (GameBeforeListener)this);
            });

            Page.On(SystemEvent.RoomStart,
                () =>
                {
                    ConnectManager.RoomService?.StartRoom();
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });

            Page.On(SystemEvent.RoomKickPlayer,
                (string userId) =>
                {
                    ConnectManager.RoomService?.Kick(userId);
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomLeavePlayer,
                () =>
                {
                    ConnectManager.RoomService?.Leave();
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomReadyPlayer,
                () =>
                {
                    ConnectManager.RoomService?.Ready();
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomCancelPlayer,
                () =>
                {
                    ConnectManager.RoomService?.Cancel();
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomChangePlayer,
                (JSONObject data) =>
                {
                    ConnectManager.RoomService?.Change(Encoding.UTF8.GetBytes(data.ToString()));
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomCreate,
                (JSONObject data) =>
                {
                    var number = data["playerTotal"];
                    ConnectManager.RoomService?.CreateRoom(Encoding.UTF8.GetBytes(data.ToString()), number, Game.GetVersion());
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomDisband,
                (JSONObject data) =>
                {
                    //TODO 房主解散
                    ConnectManager.RoomService?.Disband();
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomChange,
                (JSONObject data) =>
                {
                    ConnectManager.RoomService?.ChangeRoom(Encoding.UTF8.GetBytes(data.ToString()));
                    // RoomConnect.LeaveGame(exit, () =>
                    // {
                    //
                    // });

                });
            Page.On(SystemEvent.RoomAll,
                () =>
                {
                    try
                    {
                        ConnectManager.RoomService?.RequestAllRooms();
                    }
                    catch (Exception e)
                    {
                        Debug.LogError(e);
                    }
                });
            Page.On(SystemEvent.RoomBack, () =>
            {
                ConnectManager.RoomService?.Back();
            });
            Page.On(SystemEvent.RoomAllPlayer, () =>
            {
                ConnectManager.RoomService?.GetAllClient();
            });
        }

        protected void UiFinish()
        {
            if (OnUiFinishEvent != null) OnUiFinishEvent();
        }

        public virtual void StartPlay()
        {
        }

        public virtual void EndPlay()
        {
        }
    }
}